package com.voe.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

import com.voe.VoEAudioProcessing;
import com.voe.VoEBase;
import com.voe.VoECodec;
import com.voe.VoEDtmf;
import com.voe.VoEEncryption;
import com.voe.VoEErrors;
import com.voe.VoEExternalMedia;
import com.voe.VoEFile;
import com.voe.VoEHardware;
import com.voe.VoENetEqStats;
import com.voe.VoENetwork;
import com.voe.VoERTP_RTCP;
import com.voe.VoEVideoSync;
import com.voe.VoEVolumeControl;
import com.voe.VoiceEngine;
import com.voe.callback.VoiceEngineObserver;
import com.voe.common.AgcModes;
import com.voe.common.CodecInst;
import com.voe.common.EcModes;
import com.voe.common.OnHoldModes;
import com.voe.common.ReturnValue;
import com.voe.common.TraceLevel;

public class voe_cmd_test {

	static class MyObserver extends VoiceEngineObserver {

		@Override
		public void callbackOnError(int channel, int errCode) {
			VoEErrors err_code = VoEErrors.fromValue(errCode);
			// Add printf for other error codes here
			if (err_code == VoEErrors.VE_TYPING_NOISE_WARNING) {
				printf("  TYPING NOISE DETECTED \n");
			} else if (err_code == VoEErrors.VE_RECEIVE_PACKET_TIMEOUT) {
				printf("  RECEIVE PACKET TIMEOUT \n");
			} else if (err_code == VoEErrors.VE_PACKET_RECEIPT_RESTARTED) {
				printf("  PACKET RECEIPT RESTARTED \n");
			} else if (err_code == VoEErrors.VE_RUNTIME_PLAY_WARNING) {
				printf("  RUNTIME PLAY WARNING \n");
			} else if (err_code == VoEErrors.VE_RUNTIME_REC_WARNING) {
				printf("  RUNTIME RECORD WARNING \n");
			} else if (err_code == VoEErrors.VE_SATURATION_WARNING) {
				printf("  SATURATION WARNING \n");
			} else if (err_code == VoEErrors.VE_RUNTIME_PLAY_ERROR) {
				printf("  RUNTIME PLAY ERROR \n");
			} else if (err_code == VoEErrors.VE_RUNTIME_REC_ERROR) {
				printf("  RUNTIME RECORD ERROR \n");
			} else if (err_code == VoEErrors.VE_REC_DEVICE_REMOVED) {
				printf("  RECORD DEVICE REMOVED \n");
			}
		}
	}

	static VoiceEngine m_voe;
	static VoEBase base1;
	static VoECodec codec;
	static VoEVolumeControl volume;
	static VoEDtmf dtmf;
	static VoERTP_RTCP rtp_rtcp;
	static VoEAudioProcessing apm;
	static VoENetwork netw;
	static VoEFile file;
	static VoEVideoSync vsync;
	static VoEEncryption encr;
	static VoEHardware hardware;
	static VoEExternalMedia xmedia;
	static VoENetEqStats neteqst;

	static void printf(String format) {
		System.out.print(format);
	}

	static int getLineNumber() {
		StackTraceElement ste = new Throwable().getStackTrace()[1];
		return ste.getLineNumber();
	}

	static void VALIDATE(int res, int cnt, int line) {
		if (res != 0) {
			System.err.printf("*** Error at position %d / line %d \n", cnt, line);
			System.err.printf("*** Error code = %d \n", base1.lastError());
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int res = 0;
		int cnt = 0;

		m_voe = VoiceEngine.createInstance();
		base1 = VoEBase.createInstance(m_voe);
		codec = VoECodec.createInstance(m_voe);
		apm = VoEAudioProcessing.createInstance(m_voe);
		volume = VoEVolumeControl.createInstance(m_voe);
		dtmf = VoEDtmf.createInstance(m_voe);
		rtp_rtcp = VoERTP_RTCP.createInstance(m_voe);
		netw = VoENetwork.createInstance(m_voe);
		file = VoEFile.createInstance(m_voe);
		vsync = VoEVideoSync.createInstance(m_voe);
		encr = VoEEncryption.createInstance(m_voe);
		hardware = VoEHardware.createInstance(m_voe);
		xmedia = VoEExternalMedia.createInstance(m_voe);
		neteqst = VoENetEqStats.createInstance(m_voe);

		MyObserver my_observer = new MyObserver();

		String out_path = OutputPath();
		;
		String trace_filename = out_path + "webrtc_trace.txt";

		printf("Set trace filenames (enable trace)\n");

		res = VoiceEngine.setTraceFilter(TraceLevel.kTraceAll);
		VALIDATE(res, cnt++, getLineNumber());
		res = VoiceEngine.setTraceFile(trace_filename);
		VALIDATE(res, cnt++, getLineNumber());

		res = VoiceEngine.setTraceCallback(null);
		VALIDATE(res, cnt++, getLineNumber());

		printf("Init\n");
		res = base1.init();
		VALIDATE(res, cnt++, getLineNumber());

		res = base1.registerVoiceEngineObserver(my_observer);
		VALIDATE(res, cnt++, getLineNumber());

		printf("Version\n");
		printf(String.format("%s\n", base1.getVersion()));

		try {
			RunTest(out_path);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		printf("Terminate \n");
		base1.deRegisterVoiceEngineObserver();

		res = base1.terminate();
		VALIDATE(res, cnt++, getLineNumber());

		if (base1 != null)
			base1.release();

		if (codec != null)
			codec.release();

		if (volume != null)
			volume.release();

		if (dtmf != null)
			dtmf.release();

		if (rtp_rtcp != null)
			rtp_rtcp.release();

		if (apm != null)
			apm.release();

		if (netw != null)
			netw.release();

		if (file != null)
			file.release();

		if (vsync != null)
			vsync.release();

		if (encr != null)
			encr.release();

		if (hardware != null)
			hardware.release();

		if (xmedia != null)
			xmedia.release();

		if (neteqst != null)
			neteqst.release();

		if (m_voe != null)
			m_voe.release();
	}

	static String kPathDelimiter = "\\";
	static String kOutputDirName = "out";
	static String kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR";
	static String kProjectRootFileName = "DEPS";
	static String kFallbackPath = "./";
	static String relative_dir_path = "";
	static boolean relative_dir_path_set = false;

	private static String OutputPath() {
		String path = ProjectRootPath();
		if (path == kCannotFindProjectRootDir) {
			return kFallbackPath;
		}
		path += kOutputDirName;
		File dir = new File(path);
		if (!dir.mkdirs()) {
			return kFallbackPath;
		}
		return path + kPathDelimiter;
	}

	private static String ProjectRootPath() {

		String path = WorkingDir();
		
		return path + kPathDelimiter;
		
		/*
		if (path == kFallbackPath) {
			return kCannotFindProjectRootDir;
		}
		if (relative_dir_path_set) {
			path = path + kPathDelimiter + relative_dir_path;
		}
		// Check for our file that verifies the root dir.

		int path_delimiter_index = path.lastIndexOf(kPathDelimiter);
		while (path_delimiter_index != -1) {
			String root_filename = path + kPathDelimiter + kProjectRootFileName;
			File file = new File(root_filename);
			if (file.exists()) {
				return path + kPathDelimiter;
			}
			// Move up one directory in the directory tree.
			path = path.substring(0, path_delimiter_index);
			path_delimiter_index = path.lastIndexOf(kPathDelimiter);
		}
		// Reached the root directory.
		System.err.print("Cannot find project root directory!\n");
		return kCannotFindProjectRootDir;
		*/
	}
	
	private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	
	private static int readInt() {
		int result = 0;
		while(true) {
			try {
				result = Integer.parseInt(br.readLine());
				break;
			} catch (Exception e) {
				System.out.print("you must not input a number, please input integer again\n");
			}
		}
		return result;
	}

	private static String WorkingDir() {
		File dir = new File("");
		return dir.getAbsolutePath();
	}

	private static void RunTest(String out_path) throws IOException {
		int chan, res;

		int i;
		int cnt = 0;
		int codecinput;
		boolean AEC = false;
		boolean AGC = true;
		boolean rx_agc = false;
		boolean VAD = false;
		boolean NS = false;
		boolean rx_ns = false;
		boolean typing_detection = false;
		ReturnValue<Boolean> muted = new ReturnValue<Boolean>();
		ReturnValue<Boolean> on_hold = new ReturnValue<Boolean>();
		ReturnValue<CodecInst> cinst = new ReturnValue<CodecInst>();

		String resource_path = ProjectRootPath();

		if (resource_path == null || resource_path.isEmpty()) {
			printf("*** Unable to get project root directory. File playing may fail. ***\n");
			// Fall back to the current directory.
			resource_path = "./";
		} else {
			resource_path += "data/voice_engine/";
		}

		String audio_filename = resource_path + "audio_long16.pcm";

		String play_filename = out_path + "recorded_playout.pcm";
		String mic_filename = out_path + "recorded_mic.pcm";

		chan = base1.createChannel();
		if (chan < 0) {
			printf(String.format("Error at position %d\n", cnt));
			printf(String.format("************ Error code = %d\n",
					base1.lastError()));
		}
		cnt++;


		int j = 0;
		// #ifdef EXTERNAL_TRANSPORT
		// my_transportation ch0transport;
		// printf("Enabling external transport \n");
		// netw->RegisterExternalTransport(0, ch0transport);
		// #else
		String ip;
		ReturnValue<String> ipAddr = new ReturnValue<String>();
		netw.getLocalIP(ipAddr);
		printf(String.format("local IP:%s\n", ipAddr));
		printf("1. 127.0.0.1 \n");
		printf("2. Specify IP \n");

		i = readInt();
		// ASSERT_EQ(1, scanf("%d", &i));

		if (1 == i)
			ip = "127.0.0.1";
		else {
			printf("Specify remote IP: ");
			ip = br.readLine();
		}

		boolean colons = false;
		colons = ip.indexOf(":") != -1;

		if (colons) {
			printf("Enabling IPv6\n");
			res = netw.enableIPv6(0);
			VALIDATE(res, cnt++, getLineNumber());
		}

		printf("Specify remote port (1=1234): ");
		int rPort = readInt();
		// ASSERT_EQ(1, scanf("%d", &rPort));
		if (1 == rPort)
			rPort = 1234;
		printf("Set Send port \n");

		printf("Set Send IP \n");
		res = base1.setSendDestination(chan, rPort, ip);
		VALIDATE(res, cnt++, getLineNumber());

		printf("Specify local port (1=1234): ");
		int lPort = readInt();
		// ASSERT_EQ(1, scanf("%d", &lPort));
		if (1 == lPort)
			lPort = 1234;
		printf("Set Rec Port \n");
		res = base1.setLocalReceiver(chan, lPort);
		VALIDATE(res, cnt++, getLineNumber());

		printf("\n");
		for (i = 0; i < codec.numOfCodecs(); i++) {
			res = codec.getCodec(i, cinst);
			VALIDATE(res, cnt++, getLineNumber());
			if (cinst.getValue().plname.regionMatches(true, 0, "ISAC", 0, 4)
					&& cinst.getValue().plfreq == 32000) {
				printf(String.format(
						"%d. ISAC-swb pltype:%d plfreq:%d channels:%d\n", i,
						cinst.getValue().pltype, cinst.getValue().plfreq,
						cinst.getValue().channels));
			} else if (cinst.getValue().plname.regionMatches(true, 0, "ISAC",
					0, 4) && cinst.getValue().plfreq == 48000) {
				printf(String.format(
						"%d. ISAC-fb pltype:%d plfreq:%d channels:%d\n", i,
						cinst.getValue().pltype, cinst.getValue().plfreq,
						cinst.getValue().channels));
			} else {
				printf(String.format(
						"%d. %s pltype:%d plfreq:%d channels:%d\n", i,
						cinst.getValue().plname, cinst.getValue().pltype,
						cinst.getValue().plfreq, cinst.getValue().channels));
			}
		}
		printf("Select send codec: ");
		codecinput = readInt();
		// ASSERT_EQ(1, scanf("%d", &codecinput));
		codec.getCodec(codecinput, cinst);

		printf("Set primary codec\n");
		res = codec.setSendCodec(chan, cinst.getValue());
		VALIDATE(res, cnt++, getLineNumber());

		int kMaxNumChannels = 8;
		int channel_index = 0;
		int[] channels = new int[kMaxNumChannels];
		for (i = 0; i < kMaxNumChannels; ++i) {
			channels[i] = base1.createChannel();
			int port = rPort + (i + 1) * 2;
			res = base1.setSendDestination(channels[i], port, ip);
			VALIDATE(res, cnt++, getLineNumber());
			res = base1.setLocalReceiver(channels[i], port);
			VALIDATE(res, cnt++, getLineNumber());
			res = codec.setSendCodec(channels[i], cinst.getValue());
			VALIDATE(res, cnt++, getLineNumber());
		}

		// Call loop
		boolean newcall = true;
		while (newcall) {

			res = codec.setVADStatus(0, VAD);
			VALIDATE(res, cnt++, getLineNumber());

			res = apm.setAgcStatus(AGC);
			VALIDATE(res, cnt++, getLineNumber());

			res = apm.setEcStatus(AEC);
			VALIDATE(res, cnt++, getLineNumber());

			res = apm.setNsStatus(NS);
			VALIDATE(res, cnt++, getLineNumber());

			printf("\n1. Send, listen and playout \n");
			printf("2. Send only \n");
			printf("3. Listen and playout only \n");
			printf("Select transfer mode: ");
			i = readInt();
			// ASSERT_EQ(1, scanf("%d", &i));
			boolean send = !(3 == i);
			boolean receive = !(2 == i);

			if (receive) {
				// #ifndef EXTERNAL_TRANSPORT
				printf("Start Listen \n");
				res = base1.startReceive(chan);
				VALIDATE(res, cnt++, getLineNumber());
				// #endif

				printf("Start Playout \n");
				res = base1.startPlayout(chan);
				VALIDATE(res, cnt++, getLineNumber());
			}

			if (send) {
				printf("Start Send \n");
				res = base1.startSend(chan);
				VALIDATE(res, cnt++, getLineNumber());
			}

			printf("Getting mic volume \n");
			ReturnValue<Integer> vol = new ReturnValue<Integer>();
			res = volume.getMicVolume(vol);
			VALIDATE(res, cnt++, getLineNumber());
			if ((vol.getValue() > 255) || (vol.getValue() < 1)) {
				printf("\n****ERROR in GetMicVolume");
			}

			boolean forever = true;
			while (forever) {
				printf("\nActions\n");

				printf("Codec Changes\n");
				for (i = 0; i < codec.numOfCodecs(); i++) {
					res = codec.getCodec(i, cinst);
					VALIDATE(res, cnt++, getLineNumber());
					if (cinst.getValue().plname.regionMatches(false, 0, "ISAC",
							0, 4) && cinst.getValue().plfreq == 32000) {
						printf(String
								.format("\t%d. ISAC-swb pltype:%d plfreq:%d channels:%d\n",
										i, cinst.getValue().pltype,
										cinst.getValue().plfreq,
										cinst.getValue().channels));
					} else {
						printf(String.format(
								"\t%d. %s pltype:%d plfreq:%d channels:%d\n",
								i, cinst.getValue().plname,
								cinst.getValue().pltype,
								cinst.getValue().plfreq,
								cinst.getValue().channels));
					}
				}
				printf("Other\n");
				int noCodecs = i - 1;
				printf(String.format("\t%d. Toggle VAD\n", i));
				i++;
				printf(String.format("\t%d. Toggle AGC\n", i));
				i++;
				printf(String.format("\t%d. Toggle NS\n", i));
				i++;
				printf(String.format("\t%d. Toggle EC\n", i));
				i++;
				printf(String.format("\t%d. Select AEC\n", i));
				i++;
				printf(String.format("\t%d. Select AECM\n", i));
				i++;
				printf(String.format("\t%d. Get speaker volume\n", i));
				i++;
				printf(String.format("\t%d. Set speaker volume\n", i));
				i++;
				printf(String.format("\t%d. Get microphone volume\n", i));
				i++;
				printf(String.format("\t%d. Set microphone volume\n", i));
				i++;
				printf(String.format(
						"\t%d. Play local file (audio_long16.pcm) \n", i));
				i++;
				printf(String.format("\t%d. Change playout device \n", i));
				i++;
				printf(String.format("\t%d. Change recording device \n", i));
				i++;
				printf(String.format("\t%d. Toggle receive-side AGC \n", i));
				i++;
				printf(String.format("\t%d. Toggle receive-side NS \n", i));
				i++;
				printf(String.format("\t%d. AGC status \n", i));
				i++;
				printf(String.format("\t%d. Toggle microphone mute \n", i));
				i++;
				printf(String.format("\t%d. Toggle on hold status \n", i));
				i++;
				printf(String.format("\t%d. Get last error code \n", i));
				i++;
				printf(String
						.format("\t%d. Toggle typing detection (for Mac/Windows only) \n",
								i));
				i++;
				printf(String.format("\t%d. Record a PCM file \n", i));
				i++;
				printf(String.format(
						"\t%d. Play a previously recorded PCM file locally \n",
						i));
				i++;
				printf(String
						.format("\t%d. Play a previously recorded PCM file as microphone \n",
								i));
				i++;
				printf(String.format(
						"\t%d. Add an additional file-playing channel \n", i));
				i++;
				printf(String.format("\t%d. Remove a file-playing channel \n",
						i));
				i++;

				printf(String.format("Select action or %d to stop the call: ",
						i));
				codecinput = readInt();
				// ASSERT_EQ(1, scanf("%d", &codecinput));

				if (codecinput < codec.numOfCodecs()) {
					res = codec.getCodec(codecinput, cinst);
					VALIDATE(res, cnt++, getLineNumber());

					printf("Set primary codec\n");
					res = codec.setSendCodec(chan, cinst.getValue());
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 1)) {
					VAD = !VAD;
					res = codec.setVADStatus(0, VAD);
					VALIDATE(res, cnt++, getLineNumber());
					if (VAD)
						printf("\n VAD is now on! \n");
					else
						printf("\n VAD is now off! \n");
				} else if (codecinput == (noCodecs + 2)) {
					AGC = !AGC;
					res = apm.setAgcStatus(AGC);
					VALIDATE(res, cnt++, getLineNumber());
					if (AGC)
						printf("\n AGC is now on! \n");
					else
						printf("\n AGC is now off! \n");
				} else if (codecinput == (noCodecs + 3)) {
					NS = !NS;
					res = apm.setNsStatus(NS);
					VALIDATE(res, cnt++, getLineNumber());
					if (NS)
						printf("\n NS is now on! \n");
					else
						printf("\n NS is now off! \n");
				} else if (codecinput == (noCodecs + 4)) {
					AEC = !AEC;
					res = apm.setEcStatus(AEC, EcModes.kEcUnchanged);
					VALIDATE(res, cnt++, getLineNumber());
					if (AEC)
						printf("\n Echo control is now on! \n");
					else
						printf("\n Echo control is now off! \n");
				} else if (codecinput == (noCodecs + 5)) {
					res = apm.setEcStatus(AEC, EcModes.kEcAec);
					VALIDATE(res, cnt++, getLineNumber());
					printf("\n AEC selected! \n");
					if (AEC)
						printf(" (Echo control is on)\n");
					else
						printf(" (Echo control is off)\n");
				} else if (codecinput == (noCodecs + 6)) {
					res = apm.setEcStatus(AEC, EcModes.kEcAecm);
					VALIDATE(res, cnt++, getLineNumber());
					printf("\n AECM selected! \n");
					if (AEC)
						printf(" (Echo control is on)\n");
					else
						printf(" (Echo control is off)\n");
				} else if (codecinput == (noCodecs + 7)) {
					ReturnValue<Integer> vol2 = new ReturnValue<Integer>();
					res = volume.getSpeakerVolume(vol2);
					VALIDATE(res, cnt++, getLineNumber());
					printf(String.format("\n Speaker Volume is %d \n",
							vol2.getValue()));
				} else if (codecinput == (noCodecs + 8)) {
					printf("Level: ");
					i = readInt();
					// ASSERT_EQ(1, scanf("%d", &i));
					res = volume.setSpeakerVolume(i);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 9)) {
					ReturnValue<Integer> vol2 = new ReturnValue<Integer>();
					res = volume.getMicVolume(vol2);
					VALIDATE(res, cnt++, getLineNumber());
					printf(String.format("\n Microphone Volume is %d \n",
							vol2.getValue()));
				} else if (codecinput == (noCodecs + 10)) {
					printf("Level: ");
					i = readInt();
					// ASSERT_EQ(1, scanf("%d", &i));
					res = volume.setMicVolume(i);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 11)) {
					res = file.startPlayingFileLocally(0, audio_filename);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 12)) {
					// change the playout device with current call
					ReturnValue<Integer> num_pd = new ReturnValue<Integer>();
					res = hardware.getNumOfPlayoutDevices(num_pd);
					VALIDATE(res, cnt++, getLineNumber());

					ReturnValue<String> dn = new ReturnValue<String>();
					ReturnValue<String> guid = new ReturnValue<String>();

					printf(String.format("\nPlayout devices (%d): \n",
							num_pd.getValue()));
					for (j = 0; j < num_pd.getValue(); ++j) {
						res = hardware.getPlayoutDeviceName(j, dn, guid);
						VALIDATE(res, cnt++, getLineNumber());
						printf(String.format("  %d: %s \n", j, dn.getValue()));
					}
					printf("Select playout device: ");
					int n = readInt();
					// ASSERT_EQ(1, scanf("%d", &n));
					// Will use plughw for hardware devices
					res = hardware.setPlayoutDevice(n);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 13)) {
					// change the recording device with current call
					ReturnValue<Integer> num_rd = new ReturnValue<Integer>();
					res = hardware.getNumOfRecordingDevices(num_rd);
					VALIDATE(res, cnt++, getLineNumber());

					ReturnValue<String> dn = new ReturnValue<String>();
					ReturnValue<String> guid = new ReturnValue<String>();

					printf(String.format("Recording devices (%d): \n",
							num_rd.getValue()));
					for (j = 0; j < num_rd.getValue(); ++j) {
						res = hardware.getRecordingDeviceName(j, dn, guid);
						VALIDATE(res, cnt++, getLineNumber());
						printf(String.format("  %d: %s \n", j, dn.getValue()));
					}

					printf("Select recording device: ");
					int n = readInt();
					// ASSERT_EQ(1, scanf("%d", &num_rd));
					printf("Setting sound devices \n");
					// Will use plughw for hardware devices
					res = hardware.setRecordingDevice(n);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 14)) {
					// Remote AGC
					rx_agc = !rx_agc;
					res = apm.setRxAgcStatus(chan, rx_agc);
					VALIDATE(res, cnt++, getLineNumber());
					if (rx_agc)
						printf("\n Receive-side AGC is now on! \n");
					else
						printf("\n Receive-side AGC is now off! \n");
				} else if (codecinput == (noCodecs + 15)) {
					// Remote NS
					rx_ns = !rx_ns;
					res = apm.setRxNsStatus(chan, rx_ns);
					VALIDATE(res, cnt++, getLineNumber());
					if (rx_ns)
						printf("\n Receive-side NS is now on! \n");
					else
						printf("\n Receive-side NS is now off! \n");
				} else if (codecinput == (noCodecs + 16)) {
					ReturnValue<AgcModes> agcmode = new ReturnValue<AgcModes>();
					ReturnValue<Boolean> enabled = new ReturnValue<Boolean>();
					res = apm.getAgcStatus(enabled, agcmode);
					VALIDATE(res, cnt++, getLineNumber());
					printf(String.format("\n AGC enable is %b, mode is %s \n",
							enabled.getValue(), agcmode.getValue()));
				} else if (codecinput == (noCodecs + 17)) {
					// Toggle Mute on Microphone
					res = volume.getInputMute(chan, muted);
					VALIDATE(res, cnt++, getLineNumber());
					boolean b = !muted.getValue().booleanValue();
					res = volume.setInputMute(chan, b);
					VALIDATE(res, cnt++, getLineNumber());
					if (b)
						printf("\n Microphone is now on mute! \n");
					else
						printf("\n Microphone is no longer on mute! \n");

				} else if (codecinput == (noCodecs + 18)) {
					// Toggle the call on hold
					ReturnValue<OnHoldModes> mode = new ReturnValue<OnHoldModes>();
					res = base1.getOnHoldStatus(chan, on_hold, mode);
					VALIDATE(res, cnt++, getLineNumber());
					res = base1.setOnHoldStatus(chan, !on_hold.getValue(),
							OnHoldModes.kHoldSendAndPlay);
					VALIDATE(res, cnt++, getLineNumber());
					if (!on_hold.getValue())
						printf("\n Call now on hold! \n");
					else
						printf("\n Call now not on hold! \n");
				}

				else if (codecinput == (noCodecs + 19)) {
					// Get the last error code and print to screen
					int err_code = base1.lastError();
					if (err_code != -1)
						printf(String.format(
								"\n The last error code was %d.\n", err_code));
				} else if (codecinput == (noCodecs + 20)) {
					typing_detection = !typing_detection;
					res = apm.setTypingDetectionStatus(typing_detection);
					VALIDATE(res, cnt++, getLineNumber());
					if (typing_detection)
						printf("\n Typing detection is now on!\n");
					else
						printf("\n Typing detection is now off!\n");
				} else if (codecinput == (noCodecs + 21)) {
					int stop_record = 1;
					int file_source = 1;
					printf("\n Select source of recorded file. ");
					printf("\n 1. Record from microphone to file ");
					printf("\n 2. Record from playout to file ");
					printf("\n Enter your selection: \n");
					file_source = readInt();
					// ASSERT_EQ(1, scanf("%d", &file_source));
					if (file_source == 1) {
						printf(String.format(
								"\n Start recording microphone as %s \n",
								mic_filename));
						res = file.startRecordingMicrophone(mic_filename);
						VALIDATE(res, cnt++, getLineNumber());
					} else {
						printf(String.format(
								"\n Start recording playout as %s \n",
								play_filename));
						res = file.startRecordingPlayout(chan, play_filename);
						VALIDATE(res, cnt++, getLineNumber());
					}
					while (stop_record != 0) {
						printf("\n Type 0 to stop recording file \n");
						stop_record = readInt();
						// ASSERT_EQ(1, scanf("%d", &stop_record));
					}
					if (file_source == 1) {
						res = file.stopRecordingMicrophone();
						VALIDATE(res, cnt++, getLineNumber());
					} else {
						res = file.stopRecordingPlayout(chan);
						VALIDATE(res, cnt++, getLineNumber());
					}
					printf("\n File finished recording \n");
				} else if (codecinput == (noCodecs + 22)) {
					int file_type = 1;
					int stop_play = 1;
					printf("\n Select a file to play locally in a loop.");
					printf(String.format("\n 1. Play %s", mic_filename));
					printf(String.format("\n 2. Play %s", play_filename));
					printf("\n Enter your selection\n");
					file_type = readInt();
					// ASSERT_EQ(1, scanf("%d", &file_type));
					if (file_type == 1) {
						printf(String.format(
								"\n Start playing %s locally in a loop\n",
								mic_filename));
						res = file.startPlayingFileLocally(chan, mic_filename,
								true);
						VALIDATE(res, cnt++, getLineNumber());
					} else {
						printf(String.format(
								"\n Start playing %s locally in a loop\n",
								play_filename));
						res = file.startPlayingFileLocally(chan, play_filename,
								true);
						VALIDATE(res, cnt++, getLineNumber());
					}
					while (stop_play != 0) {
						printf("\n Type 0 to stop playing file\n");
						stop_play = readInt();
						// ASSERT_EQ(1, scanf("%d", &stop_play));
					}
					res = file.stopPlayingFileLocally(chan);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 23)) {
					int file_type = 1;
					int stop_play = 1;
					printf("\n Select a file to play as microphone in a loop.");
					printf(String.format("\n 1. Play %s", mic_filename));
					printf(String.format("\n 2. Play %s", play_filename));
					printf("\n Enter your selection\n");
					file_type = readInt();
					// ASSERT_EQ(1, scanf("%d", &file_type));
					if (file_type == 1) {
						printf(String.format(
								"\n Start playing %s as mic in a loop\n",
								mic_filename));
						res = file.startPlayingFileAsMicrophone(chan,
								mic_filename, true);
						VALIDATE(res, cnt++, getLineNumber());
					} else {
						printf(String.format(
								"\n Start playing %s as mic in a loop\n",
								play_filename));
						res = file.startPlayingFileAsMicrophone(chan,
								play_filename, true);
						VALIDATE(res, cnt++, getLineNumber());
					}
					while (stop_play != 0) {
						printf("\n Type 0 to stop playing file\n");
						stop_play = readInt();
						// ASSERT_EQ(1, scanf("%d", &stop_play));
					}
					res = file.stopPlayingFileAsMicrophone(chan);
					VALIDATE(res, cnt++, getLineNumber());
				} else if (codecinput == (noCodecs + 24)) {
					if (channel_index < kMaxNumChannels) {
						res = base1.startReceive(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = base1.startPlayout(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = base1.startSend(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = file.startPlayingFileAsMicrophone(
								channels[channel_index], audio_filename,
								true, false);
						VALIDATE(res, cnt++, getLineNumber());
						channel_index++;
						printf(String.format("Using %d additional channels\n",
								channel_index));
					} else {
						printf("Max number of channels reached\n");
					}
				} else if (codecinput == (noCodecs + 25)) {
					if (channel_index > 0) {
						channel_index--;
						res = file.stopPlayingFileAsMicrophone(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = base1.stopSend(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = base1.stopPlayout(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						res = base1.stopReceive(channels[channel_index]);
						VALIDATE(res, cnt++, getLineNumber());
						printf(String.format("Using %d additional channels\n",
								channel_index));
					} else {
						printf("All additional channels stopped\n");
					}
				} else
					break;
			}

			if (send) {
				printf("Stop Send \n");
				res = base1.stopSend(chan);
				VALIDATE(res, cnt++, getLineNumber());
			}

			if (receive) {
				printf("Stop Playout \n");
				res = base1.stopPlayout(chan);
				VALIDATE(res, cnt++, getLineNumber());

				// #ifndef EXTERNAL_TRANSPORT
				printf("Stop Listen \n");
				res = base1.stopReceive(chan);
				VALIDATE(res, cnt++, getLineNumber());
				// #endif
			}

			while (channel_index > 0) {
				--channel_index;
				res = file.stopPlayingFileAsMicrophone(channels[channel_index]);
				VALIDATE(res, cnt++, getLineNumber());
				res = base1.stopSend(channels[channel_index]);
				VALIDATE(res, cnt++, getLineNumber());
				res = base1.stopPlayout(channels[channel_index]);
				VALIDATE(res, cnt++, getLineNumber());
				res = base1.stopReceive(channels[channel_index]);
				VALIDATE(res, cnt++, getLineNumber());
			}

			printf("\n1. New call \n");
			printf("2. Quit \n");
			printf("Select action: ");
			i = readInt();
			// ASSERT_EQ(1, scanf("%d", &i));
			newcall = (1 == i);
			// Call loop
		}

		printf("Delete channels \n");
		res = base1.deleteChannel(chan);
		VALIDATE(res, cnt++, getLineNumber());

		for (i = 0; i < kMaxNumChannels; ++i) {
			channels[i] = base1.deleteChannel(channels[i]);
			VALIDATE(res, cnt++, getLineNumber());
		}
	}
}
